package com.hp.bon.sgw.threads;

import com.hp.bon.sgw.core.ChannelServer;
import com.hp.bon.sgw.core.channel.IChannel;
import com.hp.bon.sgw.domain.Node;
import com.hp.bon.sgw.domain.SGWChannel;
import com.hp.bon.sgw.service.ConfigService;
import com.hp.bon.sgw.start.SpringContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StateMonitorThread extends TaskThread {
    private static StateMonitorThread _instance;
    public static final Logger LOG = LoggerFactory.getLogger(StateMonitorThread.class);

    public static StateMonitorThread getInstance() {
        if (_instance == null) {
            _instance = new StateMonitorThread();
        }
        return _instance;
    }

    /**
     * 先执行父类的构造函数，再执行子类的构造函数
     */
    public StateMonitorThread() {
        setName("Task-StateMonitor");
    }

    public void process() {
        checkNodeSendingStatus();
        checkChannelStatus();
        checkMachineStatus();
    }

    /**
     * 根据配置的发送队列大小和当前队列的比值，计算Node(外部网元)是否繁忙;这样在路由计算时，可以配合繁忙系数，决定(多个连接时)是否调整路由，
     * 或者按比例拒绝上游请求
     */
    public void checkNodeSendingStatus() {
        for (Node node : ConfigService.id2NodeMap.values()) {
            IChannel channel = (IChannel) ChannelServer.channelMap.get(Integer.valueOf(node.getChannelId()));
            if(channel == null){
                LOG.error("checkNodeSendingStatus channel is null channelId:"+node.getChannelId());
                return;
            }
            int sendingQueueSize = channel.getNodeSendQueueSize(node.getHostId());
            double sendQueuePercent = sendingQueueSize * 1.0D / node.getMaxSendQueueSize();
            node.setSendQueuePercent(sendQueuePercent);
            int RATIO = SpringContext.getInstance().getConfigService().getIntValue("business.fluxctrl.send_queue_per", 50);
            if (sendQueuePercent > RATIO * 1.0D / 100.0D)
                LOG.warn(node.getHostId() + " reach send_queue waring threshold:" + RATIO * 1.0D / 100.0D + ",sendQueuePercent=" + sendQueuePercent);
        }
    }

    /**
     * 当SGW启动多种协议多个侦听端口时，能够自动检测哪种协议哪个端口造成的拥塞，对其进行相应限流；
     * 正常流量的业务处理则不受影响；例如DCC流量正常，SOAP请求量大增，造成SOAP消息堵塞，则对SOAP请求限流；
     */
    public void checkChannelStatus() {
        for (IChannel channel : ChannelServer.channelMap.values()) {
            SGWChannel sgwChannel = channel.getSGWChannel();
            if (sgwChannel.getStatus() == 1) {
                int recvingQueueSize = channel.getThreadPoolQueueSize();
                // 根据配置的队列大小和当前队列大小的比值，计算Channel是否繁忙；接收消息时，检查繁忙系数，决定是否立即拒绝
                double recvingQueuePercent = recvingQueueSize * 1.0D / sgwChannel.getMaxRecvQueueSize();
                sgwChannel.setRecvQueuePercent(recvingQueuePercent);
                if (LOG.isDebugEnabled()) {
                    LOG.debug(sgwChannel.getChannelType() + "-" + sgwChannel.getChannelHost() +
                            ":QueueSize=" + recvingQueueSize + ",ThreadPoolSize=" + channel.getThreadPoolSize() + ",ActiveThread=" + channel.getThreadPoolActiveCount());
                }
                int RATIO = SpringContext.getInstance().getConfigService().getIntValue("business.fluxctrl.receive_queue_per", 50);
                if (recvingQueuePercent > RATIO * 1.0D / 100.0D)
                    LOG.warn(sgwChannel.getChannelHost() + " reach recv_queue waring threshold:" + RATIO * 1.0D / 100.0D + ", recvingQueuePercent=" + recvingQueuePercent);
            }
        }
    }
    // 4、监控系统主机的异常，如果发现CPU超负荷，则根据优先级进行相应限流；（不能全拒绝业务）
    public void checkMachineStatus() {
    }

    public static void main(String[] args) {
        getInstance().start();
    }
}
